package org.kfish.framework.helper;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.kfish.framework.annotation.Aspect;
import org.kfish.framework.log.Log;
import org.kfish.framework.log.Log.LogType;
import org.kfish.framework.proxy.AspectProxy;
import org.kfish.framework.proxy.Proxy;
import org.kfish.framework.proxy.ProxyManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AopHelper {
	static {	
		try {
			Map<Class<?>,Set<Class<?>>>proxyMap = createProxyMap();
			Map<Class<?>,List<Proxy>> targetMap = createTargetMap(proxyMap);
			
			//加到Bean容器中
			for(Entry<Class<?>,List<Proxy>> entry:targetMap.entrySet()){
				Class<?> targetClass = entry.getKey();
				List<Proxy> proxyList = entry.getValue();
				Object proxy  = ProxyManager.createProxy(targetClass, proxyList);
				BeanHelper.setBean(targetClass, proxy);
			}		
		} catch (Exception e) {
			Log.getLogger(LogType.DETAIL).error("init AopHelper failure",e);
			throw new RuntimeException(e);
		}
		
	}

	/**
	 * 获取应用包下所有带有Aspect注解的类
	 * @param aspect
	 * @return
	 */
	public static Set<Class<?>> createTargetClassSet(Aspect aspect){
		Set<Class<?>> targetClassSet = new HashSet<>(); 
		
		Class<? extends Annotation> annotation = aspect.value();
		
		if(annotation !=null && ! annotation.equals(aspect)){
			targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation));
		}
		return targetClassSet;
	}
	/**
	 * 将含有Aspect注解的类组成一个以Aspect.class为key的Map，并返回。
	 * @return
	 */
	public static Map<Class<?>,Set<Class<?>>> createProxyMap(){
		Map<Class<?>,Set<Class<?>>> proxyMap = new HashMap<>();
		
		//获取AspectProxy 的 实现类或者子类
		Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
		
		for(Class<?> proxyClass:proxyClassSet){
			//确认是否含有Aspect注解
			if(proxyClass.isAnnotationPresent(Aspect.class)){
				Aspect aspect = proxyClass.getAnnotation(Aspect.class);
				Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
						proxyMap.put(proxyClass, targetClassSet);	
 			}
			
		}	
		return proxyMap;
	}

	public static Map<Class<?>,List<Proxy>> createTargetMap(Map<Class<?>,Set<Class<?>>> proxyMap) throws Exception{
		Map<Class<?>,List<Proxy>> targetMap = new HashMap<>();
		for(Entry<Class<?>,Set<Class<?>>> entry:proxyMap.entrySet()){
			Class<?> proxyClass = entry.getKey();
			Set<Class<?>> targetClassSet = entry.getValue();
			
			for(Class<?> targetClass:targetClassSet){
				//不同的类，使用同一个代理
				Proxy proxy = (Proxy) proxyClass.newInstance();
				if(targetMap.containsKey(targetClass)){
					targetMap.get(targetClass).add(proxy);
				}else{
					List<Proxy> proxyList = new ArrayList<>();
					proxyList.add(proxy);
					targetMap.put(targetClass, proxyList);
				}
			}
		}
		return targetMap;
	}

}
